#ifndef _ML_MOVESTREAM_DATA_CLUSTERING_H_
#define _ML_MOVESTREAM_DATA_CLUSTERING_H_
#include "MLCommon.h"
#include "MLDataSet.h"
#include "MLDataVector.h"
#include "MLDataPoint.h"
#include "MLDistanceFunctions.h"
#include "MLDataClustering.h"

using namespace mylablib;


class CMLMovStream;

struct CMLMovStreamClusterEvent
{
public:
	// Types
	enum ClusterEventType
	{
		ClusterEvent_None,
		ClusterEvent_Drift,
		ClusterEvent_Expand,
		ClusterEvent_Shrink,
		ClusterEvent_DieOut,
		ClusterEvent_Merge,
		ClusterEvent_Split,
		ClusterEvent_ThrowOut,
	};

public:
	// Methods
	inline std::wstring ToWString(void) const
	{
		std::wstringstream tempStream;
		switch(nEvent)
		{
		case ClusterEvent_Drift:
			tempStream << L"DRIFT " << nCluster;
			break;
		case ClusterEvent_Expand:
			tempStream << L"EXPAND " << nCluster;
			break;
		case ClusterEvent_Shrink:
			tempStream << L"SHRINK " << nCluster;
			break;
		case ClusterEvent_DieOut:
			tempStream << L"DIEOUT " << nCluster;
			break;
		case ClusterEvent_Merge:
			tempStream << L"MERGE " << nCluster << L',' << nCluster2; 
			break;
		case ClusterEvent_Split:
			tempStream << L"SPLIT " << nCluster; 
			break;
		case ClusterEvent_ThrowOut:
			tempStream << L"THROWOUT " << nCluster; 
			break;
		}
		return tempStream.str();
	}

public:
	// Fields
	int nEvent;
	int nCluster;
	int nCluster2;
};


class CMLMovStreamCluster
{
public:
	// Constructor and Destructor
	CMLMovStreamCluster(CMLMovStream* pClustering, int nID);
	~CMLMovStreamCluster(void);

public:
	// Methods
	int  Create(const CMLDataSet& dataSet);
	int  Absorb(const CMLDataPoint& dataPoint, int nTime);
	int  Popout(int nTimeDeadline);
	int  Reset(void);

public:
	// Events
	bool TriggerDriftEvent(void);
	bool TriggerExpandEvent(void);
	bool TriggerShrinkEvent(void);
	bool TriggerDieOutEvent(void);
	bool TriggerSplitEvent(void);
	bool TriggerMergeEvent(CMLMovStreamCluster* pNearCluster);
	int  ExecuteMove(void);
	int  ExecuteSplit(CMLMovStreamCluster* pNewCluster);
	int  ExecuteStretch(void);
	int  ExecuteDieOut(void);
	int  ExecuteMerge(CMLMovStreamCluster* pNearCluster);
	int  ExecuteThrowOut(void);

public:
	// Properties
	inline int   GetSWLength() const { return (int)m_SlideWindow.size(); };

	inline CMLDataPoint GetCenter() const
	{
		return m_vLS / GetSWLength(); 
	}

	inline double GetRadius() const 
	{ 
		int N = GetSWLength();
		CMLDataPoint tmp = (m_vSS/N) - ((m_vLS/N)^2);
		return sqrt(tmp.Norm1());
	}

	inline int GetID() const { return m_nID; };

	inline double GetAvgTimeStamp(int nNumLast) const
	{
		double dAvgTime = 0.0;
		std::list<SlideWindowElem_>::const_iterator Iter = m_SlideWindow.end();
		Iter--;
		while(Iter != m_SlideWindow.begin() && nNumLast > 0)
		{
			dAvgTime += (*Iter).nTime;
			Iter--;
		}
		return dAvgTime / min(nNumLast, GetSWLength());
	}

private:
	// Types
	struct SlideWindowElem_
	{
		CMLDataPoint dataPoint;
		int nTime;
	};

private:
	// Fields
	std::list<SlideWindowElem_> m_SlideWindow;
	CMLDataPoint m_OriginCenter;
	double m_dOriginRadius;

	CMLDataPoint m_vLS;
	CMLDataPoint m_vSS;

	CMLMovStream* m_pClustering;
	IMLDataPointDistanceFunc* m_pDistFunc;
	int m_nID;
};

class CMLMovStream : public CMLIncrementalDataClustering
{
public:
	// Constructor and Destructor
	CMLMovStream(void);
	~CMLMovStream(void);

public:
	// Interfaces
	int SetParameters(const std::wstring& wstrParams);
	int Insert(const CMLDataPoint& dataPoint);
	int GetClusters(const std::wstring& params, std::vector<CMLDataCluster>& vClusters);

public:
	// Methods
	int CheckClustersEvents(std::vector<CMLMovStreamClusterEvent>& vEvents);
	int Release(void);

	inline IMLDataPointDistanceFunc* GetDistanceFunc() const { return m_pDistFunc; };
	inline void SetDistanceFunc(IMLDataPointDistanceFunc* pFunc) { m_pDistFunc = pFunc; };


private:
	// Inner Types

public:
	// Properties
	inline void SetNumInitClusters(int nNum)     { m_nNumInitClusters = nNum; };
	inline int  GetNumClusters(void) const    { return (int)m_vpMicroClusters.size(); };
	inline void SetInitNumber(int nNum)       { m_nInitNumber = nNum; };
	inline int  GetInitNumber(void) const     { return m_nInitNumber; };
	inline void SetMaxNumClusters(int nMax)   { m_nNumMaxClusters = nMax; };
	inline void SetMinNumClusters(int nMin)   { m_nNumMinClusters = nMin; };
	
	inline void SetMaxRadius(double max) { m_dMaxRadius = max; };
	inline double GetMaxRadius(void) const { return m_dMaxRadius; };
	inline void SetMaxDriftFactor(double factor) { m_dMaxDriftFactor = factor; };
	inline double GetMaxDriftFactor(void) const { return m_dMaxDriftFactor; };
	inline void SetStretchFactor(double factor) { m_dStretchFactor = factor; };
	inline double GetStretchFactor(void) const { return m_dStretchFactor; };
	
	inline void SetMaxAge(double age) { m_dMaxAge = age; };
	inline double GetMaxAge(void) const { return m_dMaxAge; };
	inline void SetNumLastTimeStampCheck(int nNumLast) { m_nNumLastTimeStampCheck = nNumLast; };
	inline int GetNumLastTimeStampCheck(void) { return m_nNumLastTimeStampCheck; };

	inline void SetMergeFactor(double factor) { m_dMergeFactor = factor; };
	inline double GetMergeFactor(void) const { return m_dMergeFactor; };
	inline void SetMinDataPointNumberRatio(double ratio) { m_dMinDataPointNumberRatio = ratio; };
	inline double GetMinDataPointNumberRatio(void) const { return m_dMinDataPointNumberRatio; };

	inline int  GetTotalPointNumber(void) const { return m_nDataPointTotalNumber; };
	inline int  GetCurTimeCounter(void) const { return m_nTimeCounter; };
	inline std::vector<CMLMovStreamCluster*>& GetMicroClusters(void) { return m_vpMicroClusters; };
	inline void SetTotalSWLength(int nLen) { m_nTotalSWLength = nLen; };
	inline int  GetTotalSWLength(void) const { return m_nTotalSWLength; };

private:
	// Implementations
	int CreateClusters(void);
	int FindNearestCluster(const CMLDataPoint& point);
	int GrowNewCluster(void);
	
protected:
	// Fields
	IMLDataPointDistanceFunc* m_pDistFunc;

private:
	// Fields
	std::vector<CMLMovStreamCluster*> m_vpMicroClusters;
	CMLDataSet m_DataSet;
	int        m_nNumInitClusters;
	int        m_nNumMaxClusters;
	int        m_nNumMinClusters;
	int        m_nNumLastTimeStampCheck;
	int        m_nTotalSWLength;

	int        m_nInitNumber;
	int        m_nDataPointTotalNumber;
	double     m_dMaxRadius;
	double     m_dMaxDriftFactor;
	double     m_dStretchFactor;
	double     m_dMaxAge;
	double     m_dMergeFactor;
	double     m_dMinDataPointNumberRatio;
	int        m_nTimeCounter;
	int        m_nClusterIdCounter;
};



#endif
